'''
Created on Mar 29, 2010

@author: jhlee
'''
from DisplayObject3D import *
from Matrix44 import *
from Number3D import *
from Quaternion import *

from OpenGL.GL import *
from OpenGL.GLU import *

DEFAULT_POS_X = 0
DEFAULT_POS_Y = 0
DEFAULT_POS_Z = 1000

DEFAULT_UP = Number3D(0,1,0) 

class Camera:
    def __init__(self):
        self.orientation = Quaternion()
        self.position = Number3D()
        self.at = Number3D()
        self.up = Number3D()
        
        self.derivedOrientation = Quaternion()
        self.derivedPosition = Number3D()
        
        self.recalcWindow = True
        
        self.cachedViewToWorld = Matrix44()
        
        # Projection definition
        self.fovy = 45
        self.far = 10000
        self.near = 1
        self.aspect = 1.3333
        
        self.parentNode = None
        
    def setParentNode(self, parent):
        self.parentNode = parent
        
    def setPosition(self, x, y, z):
        self.position.set(x,y,z)
        self.invalidateView()
        
    def getPosition(self):
        return self.position
    
    def lookAt(self, x, y, z):
        self.at.set(x, y, z)
        self.invalidateView()
                
    def updateView(self):
        pass
    
    def move(self, v):
        self.position.add(v)
        self.invalidateView()
        
    def invalidateView(self):
        self.recalcWindow = True
        
    def setUpVector(self, x, y, z):
        self.up.set(x,y,z)
        self.invalidateView()
        
        
    def getUpVector(self):
        return self.up
        
    
    def getViewMatrix(self):
        if self.recalcWindow:
            self.updateViewToWorldMatrix()
            
        return self.cachedViewToWorld

    def getProjectionMatrix(self):
        pass
    
    def updateViewToWorldMatrix(self):
        self.recalcWindow = False
        
        dir = Number3D(self.at.x, self.at.y, self.at.z)
        dir.sub(self.position)
        dir.normalize()
        
        side = Number3D()
        dir.cross(self.up, side)
        side.normalize()
        
        up = Number3D()
        side.cross(dir, up)
        up.normalize()
        
        m = self.cachedViewToWorld
        m.n11 = side.x
        m.n12 = side.y
        m.n13 = side.z 
        m.n14 = side.x*-self.position.x +  side.y*-self.position.y + side.z*-self.position.z
        
        m.n21 = up.x
        m.n22 = up.y 
        m.n23 = up.z 
        m.n24 = up.x*-self.position.x + up.y*-self.position.y + up.z*-self.position.z
        
        m.n31 = dir.x
        m.n32 = dir.y
        m.n33 = dir.z
        m.n34 = dir.x*-self.position.x + dir.y * -self.position.y + dir.z * -self.position.z
        
        m.n41 = m.n42 = m.n43 = 0
        m.n44 = 1
        
        
    def setupForRendering(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(self.fovy, self.aspect, self.near, self.far)
        
        glMatrixMode(GL_MODELVIEW)
        
        #glLoadMatrixf(self.getViewMatrix().toArray())
        gluLookAt(self.position.x, self.position.y, self.position.z,
                  self.at.x, self.at.y, self.at.z,
                  self.up.x, self.up.y, self.up.z)
        
        
        